package com.kajespero.json.helper;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ClassHelper {
	
	private static final Log LOG = LogFactory.getLog(ClassHelper.class);

	
	public static <E, A extends Annotation> Collection<Field> getField(Class<E> clazz, Class<A> annotationClazz){
		List<Field> fields = new ArrayList<Field>();
		Field[] attributes = clazz.getDeclaredFields();
		for (Field attribute : attributes) {
			Annotation annotation = attribute.getAnnotation(annotationClazz);
			if (annotation != null ) {
				fields.add(attribute);
			}
		}
		return fields;
	}
	
	public static <E, A extends Annotation> A getDeclaredAnnotation(Class<E> clazz, Class<A> annotationClass){
		A annotation = clazz.getAnnotation(annotationClass);
		return annotation;
	}
	
	public static <E> E newInstance(Class<E> clazz){
		try {
			E instance = clazz.newInstance();
			return instance;
		} catch (InstantiationException e) {
			LOG.error("InstantiationException " + e.getMessage(), e);
			return null;
		} catch (IllegalAccessException e) {
			LOG.error("IllegalAccessException " + e.getMessage(), e);
			return null;
		}
	}
	
	public static <E> void setField(Field field, E instance, Object value){
		if(field != null){
			field.setAccessible(true);
			try {
				Class<?> classField = field.getType();
				Class<?> classValue = value.getClass();
				if(classField.getName().equals(classValue.getName())){
					field.set(instance, value);
				}
				else {
					field.set(instance, NumberUtils.convert(value, classField));
				}
			} catch (IllegalArgumentException e) {
				LOG.error("IllegalArgumentException " + e.getMessage(), e);
			} catch (IllegalAccessException e) {
				LOG.error("IllegalAccessException " + e.getMessage(), e);
			}
			finally{
				field.setAccessible(false);
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public static <E, T> T getField(Field field, E instance){
		try {
			field.setAccessible(true);
			return (T) field.get(instance);
		} catch (IllegalArgumentException e) {
			LOG.error("IllegalArgumentException " + e.getMessage(), e);
		} catch (IllegalAccessException e) {
			LOG.error("IllegalAccessException " + e.getMessage(), e);
		}
		finally{
			field.setAccessible(false);
		}
		
		return null;
	}
	
	public static <T> Object getValue(T instance, String attribute){
		Field field  = getField(instance.getClass(), attribute);
		if(field != null){
			
			try {
				field.setAccessible(true);
				return field.get(instance);
			} catch (IllegalArgumentException e) {
				LOG.error("IllegalArgumentException " + e.getMessage(), e);
			} catch (IllegalAccessException e) {
				LOG.error("IllegalAccessException " + e.getMessage(), e);
			}
			finally{
				field.setAccessible(false);
			}
		}
		return null;
 	}
	
	
	public static Field getField(Class<?> clazz, String attribute){
		Field [] fields = clazz.getDeclaredFields();
		for (Field field : fields){
			if(field.getName().equals(attribute)){
				return field;
			}
		}
		return null;
	}
	
	public static <T> void setValue(T instance, String attribute, Object value){
		Field field = getField(instance.getClass(), attribute);
		if(field != null){
			field.setAccessible(true);
			try {
				field.set(instance, value);
			} catch (IllegalArgumentException e) {
				LOG.error("IllegalArgumentException " + e.getMessage(), e);
			} catch (IllegalAccessException e) {
				LOG.error("IllegalAccessException " + e.getMessage(), e);
			}
			finally{
				field.setAccessible(false);
			}
			
		}
	}
}
